package autotd.server;

import java.net.*;

import java.util.*;
import java.awt.Point;
import java.io.*;

import autotd.*;

public class SimulatorClient extends AdvancedSimulatorListenerClient implements AdvancedSimulatorListener {
	private Socket commanderSocket;
	private PrintWriter commanderOut;
	private BufferedReader commanderIn;
	private TDSimulator myCore;

	public SimulatorClient(TDSimulator core) throws Exception {
		super();
		myCore = core;
		addAdvancedListener(this);
		commanderSocket = new Socket("localhost", DEFAULT_PORT_NUMBER);
		commanderOut = new PrintWriter(commanderSocket.getOutputStream());
		commanderIn = new BufferedReader(new InputStreamReader(commanderSocket.getInputStream()));
		waitForMessage(commanderIn, CONNECTED_RESPONSE);
		commanderOut.println(COMMANDER_REQUEST);
		commanderOut.flush();
		waitForMessage(commanderIn, ACK);
	}

	
	public boolean sendCommand(String cmd) {
		commanderOut.println(cmd);
		commanderOut.flush();
		return getResponse(commanderIn);
	}

	public boolean tick() {
		return sendCommand("TICK 1");
	}

	public boolean placeTower(TowerType type, int x, int y) {
		return sendCommand("PLACE_TOWER " + x + " " + y + " " + type.Name);
	}
	
	public boolean shootMonster(Point p, Monster target) {
		return sendCommand("FIRE_TOWER " + p.x + " " + p.y + " " + target.id);
	}



	public GameMap getMap() {
		return myCore.getMap();
	}
	
	public Player getPlayer() {
		return myCore.getPlayer();
	}
	
	public Set<Monster> getActiveMonsters() {
		return myCore.getActiveMonsters();
	}
	
	public Set<Tower> getPlacedTowers() {
		return myCore.getPlacedTowers();
	}

	public int getTurnNumber() {
		return myCore.getTurnNumber();
	}

	public List<MonsterType> getMonsterTypes() {
		return myCore.getMonsterTypes();
	}

	public Map<String, MonsterType> getMonsterTypesMap() {
		return myCore.getMonsterTypesMap();
	}

	public List<TowerType> getTowerTypes() {
		return myCore.getTowerTypes();
	}

	public Map<String, TowerType> getTowerTypesMap() {
		return myCore.getTowerTypesMap();
	}
	
	public TowerType getTowerType(String name) {
		return myCore.getTowerType(name);
	}

	public MonsterType getMonsterType(String name) {
		return myCore.getMonsterType(name);
	}
	
	public Set<Tower> getTowers() {
		return myCore.getTowers();
	}

	public Tower lookupTower(int id){
		return myCore.lookupTower(id);
	}
	
	public Monster lookupMonster(int id){
		return myCore.lookupMonster(id);
	}




	public void monsterCreated(int mID, String type, int level, int x, int y) {
		Monster m = new Monster(getMonsterType(type), level);
		m.id = mID;
		m.pos = new Point(x, y);
		myCore.monsters.add(m);
		myCore.map.add(m, m.pos);
	}

	public void monsterMoved(int mID, int prevX, int prevY, int currX, int currY) {
		Monster m = lookupMonster(mID);
		myCore.map.remove(m);
		myCore.map.add(m, new Point(currX, currY));
	}

	public void monsterInjured(int mID, int health) {
		Monster m = lookupMonster(mID);
		m.health = health;
	}

	public void monsterCompletedPath(int mID) {
		myCore.player.hit(1);
		myCore.map.remove(lookupMonster(mID));
		myCore.monsters.remove(lookupMonster(mID));
	}

	public void towerPlaced(int tID, String type, int x, int y, int height) {
		Tower t = new Tower(getTowerType(type), myCore.map.getHeight(x, y));
		t.id = tID;
		myCore.towers.add(t);
		myCore.map.add(t, new Point(x, y));
	}

	public void towerFired(int tID, int mID) {
		myCore.lookupTower(tID).act();
	}


	public void playerChange(int lives, int money) {
		myCore.player.setLives(lives);
		myCore.player.setMoney(money);
	}

	public void turnChangedTo(int turnNum) {
		for (int gap = myCore.turn; gap < turnNum; gap++) {
			for (Tower t : myCore.getTowers()) {
				t.tick();
			}
		}
		myCore.turn = turnNum;
		cullDeadMonsters();
	}

	public void cullDeadMonsters() {
		// check for dead monsters
		for (Monster m: new HashSet<Monster>(myCore.getActiveMonsters())) {
			if (m.isDead()) {
				myCore.monsters.remove(m);
				myCore.map.remove(m);
			}
		}
	}
}









